/*
   Copyright (C) 2011 Roman Belov <romblv@gmail.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _H_LIST_
#define _H_LIST_

typedef struct list_node list_node_t;

struct list_node {
	list_node_t	*next;
	list_node_t	*prev;
};

inline void
list_up(list_node_t *head)
{
	head->next = head;
	head->prev = head;
}

inline void
list_insert(void *lhead, void *lnode)
{
	list_node_t	*head, *node;
	list_node_t	*prev;

	head = lhead;
	node = lnode;

	prev = head->prev;
	head->prev = node;
	prev->next = node;
	node->prev = prev;
	node->next = head;
}

inline void
list_insert_alt(void *lhead, void *lnode)
{
	list_node_t	*head, *node;
	list_node_t	*next;

	head = lhead;
	node = lnode;

	next = head->next;
	head->next = node;
	next->prev = node;
	node->next = next;
	node->prev = head;
}

inline void
list_remove(void *lnode)
{
	list_node_t	*node;
	list_node_t	*next, *prev;

	node = lnode;

	next = node->next;
	prev = node->prev;
	next->prev = prev;
	prev->next = next;
}

inline void
list_move(void *ldest, void *lnode)
{
	list_node_t	*dest, *node;

	dest = ldest;
	node = lnode;

	dest->next = node->next;
	dest->prev = node->prev;
	dest->next->prev = dest;
	dest->prev->next = dest;
}

inline void *
list_next(void *lnode)
{
	list_node_t	*node = lnode;

	return node->next;
}

inline void *
list_prev(void *lnode)
{
	list_node_t	*node = lnode;

	return node->prev;
}

inline int
list_is_empty(list_node_t *head)
{
	return head->next == head;
}

#define list_for_each(head, node)		\
	for (	node = list_next(head);		\
		node != (void *) (head);	\
		node = list_next(node))

#define list_for_each_safe(head, node, next)	\
	for (	node = list_next(head), next = list_next(node);	\
		node != (void *) (head);			\
		node = next, next = list_next(node))

#endif /* _H_LIST_ */

